package com.hxs.learn.aop;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.hxs.learn.common.web.HttpContext;
import com.hxs.learn.common.web.LoginInfo;
import com.hxs.learn.common.web.utils.ShiroKit;
import com.hxs.learn.entity.sys.SysLog;
import com.hxs.learn.log.LogManager;
import com.hxs.learn.log.LogTaskFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Map;

/**
 * 日志记录
 *
 * @author huxinsheng
 */
@Aspect
@Component
public class WebLogAspect {

    private final DefaultWebSecurityManager securityManager;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    public WebLogAspect(DefaultWebSecurityManager securityManager) {
        this.securityManager = securityManager;
    }

    @Pointcut("execution(public * com.hxs.learn.action.*.*.*(..))")
    public void cutService() {
    }

    @Around("cutService()")
    public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {
        SecurityUtils.setSecurityManager(securityManager);
        // 接收到请求，记录请求内容
        // 提前记录用户名，防止登出操作，取不到用户名
        String userName = "";
        if (ShiroKit.isUser()) {
            if (null != ShiroKit.getUser()) {
                userName = ((LoginInfo) ShiroKit.getUser()).getLoginName();
            }
        }
        Long start = System.currentTimeMillis();
        // 先执行业务
        Object result = point.proceed();
        try {
            handle(point, start, userName);
        } catch (Exception e) {
            logger.error("日志记录出错!", e);
        }

        return result;
    }

    private void handle(ProceedingJoinPoint point, Long start, String userName) throws Exception {
        Long end = System.currentTimeMillis();
        SysLog sysLog = new SysLog();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String requestUrl = request.getServletPath();
        sysLog.setRequestUri(requestUrl);
        sysLog.setMethod(request.getMethod());
        sysLog.setRemoteAddr(HttpContext.getIpAddr());
        sysLog.setUserAgent(request.getHeader("user-agent"));

        //登录的时候，不记录账号密码
        if (requestUrl.contains("/login") || requestUrl.contains("/logout")) {
            //登录请求
            sysLog.setLogType(SysLog.LOGTYPE_LOGIN);
        } else {
            //业务请求
            sysLog.setLogType(SysLog.LOGTYPE_REQUEST);
            Map<String, Object> param = Maps.newHashMapWithExpectedSize(7);
            Enumeration<String> enu = request.getParameterNames();
            while (enu.hasMoreElements()) {
                String paraName = enu.nextElement();
                param.put(paraName, request.getParameter(paraName));
            }
            ObjectMapper mapper = new ObjectMapper();
            String params = mapper.writeValueAsString(param);
            sysLog.setParams(params);
        }

        sysLog.setLoseTime(end - start);

        sysLog.setCreateBy(userName);
        if (logger.isDebugEnabled()) {
            logger.debug("请求日志：" + sysLog.toString());
        }
        LogManager.me().executeLog(LogTaskFactory.requestLog(sysLog));
    }
}